Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

2.x: Evaluate Schedule initialization via Callable #4585

Merged
merged 13 commits into from
Sep 26, 2016
Merged

2.x: Evaluate Schedule initialization via Callable #4585

merged 13 commits into from
Sep 26, 2016

Conversation

peter-tackage
Copy link
Contributor

This implements the solution proposed in #4572 - to initialize the Schedulers via a Callable, rather than directly via a value.

@akarnokd akarnokd changed the title Evaluate Schedule initialization via Callable 2.x: Evaluate Schedule initialization via Callable Sep 22, 2016
}

/**
* Wraps the call to the callable in try-catch and propagates thrown
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

copy paste error

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.

@@ -186,10 +187,10 @@ public static boolean isLockdown() {
* @param defaultScheduler the hook's input value
* @return the value returned by the hook
*/
public static Scheduler initComputationScheduler(Scheduler defaultScheduler) {
public static Scheduler initComputationScheduler(Callable<Scheduler> defaultScheduler) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should not it throw on a null callable? What's the point of calling with null?

Copy link
Contributor Author

@peter-tackage peter-tackage Sep 22, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was done for consistency with the existing expectations in RxJavaPluginsTest.clearIsPassthrough(), specifically:

assertNull(RxJavaPlugins.initComputationScheduler(null));
assertNull(RxJavaPlugins.initIoScheduler(null));
assertNull(RxJavaPlugins.initNewThreadScheduler(null));
assertNull(RxJavaPlugins.initSingleScheduler(null));

Should this be changed to only return null if the Callable returns null (and throw if the Callable itself is null)?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Null should not be allowed as a return value from the Callable nor from the init Function.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This would be a change, because previously the Scheduler value for RxJavaPlugins.init* was allowed to be null, as per - assertNull(RxJavaPlugins.initSingleScheduler(null));.

I will add an additional set of tests for the new behavior (something along the lines of assemblyHookCrashes).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

* @param t the callable, not null (not verified)
* @return the result of the callable call
*/
static <T> T call(Callable<T> t) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

inline this method?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure what you mean. I've tried to be consistent with the abstraction of the similar apply method. Do you think that should change?

@codecov-io
Copy link

codecov-io commented Sep 22, 2016

Current coverage is 78.17% (diff: 88.88%)

Merging #4585 into 2.x will increase coverage by 0.08%

@@                2.x      #4585   diff @@
==========================================
  Files           552        552          
  Lines         36184      36297   +113   
  Methods           0          0          
  Messages          0          0          
  Branches       5584       5602    +18   
==========================================
+ Hits          28255      28375   +120   
+ Misses         5917       5912     -5   
+ Partials       2012       2010     -2   

Powered by Codecov. Last update 24448b4...a273507

* @return the callable result if the callable is nonnull, null otherwise.
*/
static <T> T callOrNull(Callable<T> t) {
return t == null ? null : call(t);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

null should never be allowed

@akarnokd akarnokd added this to the 2.0 RC4 milestone Sep 23, 2016
static <T, R> R apply(Function<T, R> f, Callable<T> t) {
try {
T value = t.call();
ObjectHelper.requireNonNull(t, "Callable result can't be null");
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you mean to check value here instead of t

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also you could just T value = Object.requireNonNull(t.call(), "messge")

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, good find.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, that would be better. I didn't notice the return value in the signature.

SINGLE = RxJavaPlugins.initSingleScheduler(new Callable<Scheduler>() {
@Override
public Scheduler call() throws Exception {
return new SingleScheduler();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just in case call() is called multiple times by the hook, these could actually return an field of an inner class (singleton holder pattern or what's the name):

static final class SingleHolder {
    static final Scheduler DEFAULT = new SingleScheduler();
}

SINGLE = RxJavaPlugins.initiSingleScheduler(new Callable<Scheduler>() {
    @Override
    public Scheduler call() {
        return SingleHolder.DEFAULT;
    }
});

@peter-tackage
Copy link
Contributor Author

@akarnokd, Correct me if I'm wrong, but in order to avoid the evaluation of the default Scheduler instance when it is being overridden, I still need to change the onInit[single|io|new|computation]Handler signatures to be Function<Callable<Scheduler>, Scheduler> as per -

    static volatile Function<Callable<Scheduler>, Scheduler> onInitSingleHandler;

Otherwise the invocation of initSingleScheduler will cause the evaluation of the default value to pass it as a parameter to the overriding/transforming function: onInitSingleHandler.

@akarnokd
Copy link
Member

Yes, you still need Callable as the indirection but the inner class will be evaluated only if call is actually invoked.

@peter-tackage
Copy link
Contributor Author

I've added the remaining lazy initialization.

I've also fairly aggressively enforced non-null in the associated functions, for example:

public static Scheduler initIoScheduler(Callable<Scheduler> defaultScheduler) {
    ObjectHelper.requireNonNull(defaultScheduler, "Scheduler Callable can't be null");
    Callable<Scheduler>, Scheduler> f = onInitIoHandler;
    if (f == null) {
        return callRequireNonNull(defaultScheduler);
    }
    return applyRequireNonNull(f, defaultScheduler);
}

However, to me, this seems slightly out of place / over the top. Is that enforcement necessary or should the resultant null Scheduler be left unasserted and left to the eventual NullPointerException when the Scheduler is used? Either way, I'm happy to keep or remove that based upon review feedback.

@JakeWharton
Copy link
Contributor

Aggressive input validation is never over the top. If you defer checking
then the stacktrace tells you nothing about what actually caused the broken
state.

On Sun, Sep 25, 2016, 7:09 AM Peter Tackage notifications@github.com
wrote:

I've added the remaining lazy initialization.

I've also fairly aggressively enforced non-null in the associated
functions, for example:

public static Scheduler initIoScheduler(Callable defaultScheduler) {
ObjectHelper.requireNonNull(defaultScheduler, "Scheduler Callable can't be null");
Callable, Scheduler> f = onInitIoHandler;
if (f == null) {
return callRequireNonNull(defaultScheduler);
}
return applyRequireNonNull(f, defaultScheduler);
}

However, to me, this seems slightly out of place / over the top. Is that
enforcement necessary or should the resultant null Scheduler be left
unasserted and left to the eventual NullPointerException when the Scheduler
is used? Either way, I'm happy to keep or remove that based upon review
feedback.


You are receiving this because you commented.

Reply to this email directly, view it on GitHub
#4585 (comment),
or mute the thread
https://github.com/notifications/unsubscribe-auth/AAEEEYuLqRvk4Zp6D5XX5VSnIJQIam4xks5qtlZbgaJpZM4KEbRU
.

@peter-tackage
Copy link
Contributor Author

@akarnokd, all done as far as I am concerned. Do I need to anything else for this to be merged?

@akarnokd
Copy link
Member

I was waiting for you to settle with the implementation. Thanks for the contribution.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants